package gclang

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"strings"
	"sync"

	"github.com/gin-gonic/gin"
)

var (
	// langKey lang存储(gin)下标
	langKey  = "_lang_"
	langLock sync.RWMutex
	langData = map[string]map[string]interface{}{} // 语言包数据
	// defaultLang 默认lang
	defaultLang string
	// langMap 可选语言
	langMap map[string]string
	langDir string
)

func InitLang(defaultL, langD string, langM map[string]string) {
	if strings.HasSuffix(langD, "/") {
		langDir = langD + "/"
	}
	defaultLang = defaultL
	langDir = langD
	langMap = langM
}

// SetLangKey 设置lang存储下标
func SetLangKey(l string) error {
	if l == "" {
		return errors.New("lang subscript cannot be empty")
	}
	langKey = l
	return nil
}

// GetLangKey 获取lang存储下标
func GetLangKey() string {
	return langKey
}

// AppendLang 追加语言
func AppendLang(arr map[string]string) {
	for k, v := range arr {
		langMap[k] = v
	}
}

// GetLangMap 获取所有语言
func GetLangMap() map[string]string {
	return langMap
}

// GetSelectLang 获取当前选中的语言
func GetSelectLang(c *gin.Context) (lang string) {
	lang = CheckLang(c.Query(langKey))
	if lang == "" {
		if _lang, e := c.Cookie("lang"); e == nil && _lang != "" {
			lang = CheckLang(_lang)
		}
	}
	if lang == "" {
		lang = defaultLang
	}
	return
}

// CheckLang 检测语言
func CheckLang(lang string) string {
	if lang != "" {
		if _, ok := langMap[lang]; !ok {
			lang = ""
		}
	}
	return lang
}

// RmURLLangPrefix 删除url带语言的前缀
func RmURLLangPrefix(urlPath string) string {
	for k := range langMap {
		reg := regexp.MustCompile(fmt.Sprintf(`/%s\b`, k))
		if f := reg.FindString(urlPath); f != "" {
			urlPath = reg.ReplaceAllString(urlPath, "")
			break
		}
	}
	return urlPath
}

// LoadLangFile 加载语言文件
func LoadLangFile(dirArr []string) {
	for _, val := range dirArr {
		if !strings.HasPrefix(val, "/") {
			val = langDir + val
		}
		if arr, err := ioutil.ReadDir(val); err == nil {
			for _, v := range arr {
				foreachLangDir(val, v)
			}
		}
	}
}

func foreachLangDir(path string, fInfo os.FileInfo) {
	newPath := path + "/" + fInfo.Name()
	if fInfo.IsDir() {
		if arr, err := ioutil.ReadDir(newPath); err == nil {
			for _, v := range arr {
				foreachLangDir(newPath, v)
			}
		} else {
			fmt.Println("ioutil.ReadDir", err, newPath)
		}
	} else if strings.HasSuffix(fInfo.Name(), ".json") {
		_lang := fInfo.Name()[:len(fInfo.Name())-5]
		if _, ok := langMap[_lang]; ok {
			if byteData, err := ioutil.ReadFile(newPath); err == nil {
				data := map[string]interface{}{}
				if err = json.Unmarshal(byteData, &data); err == nil {
					langLock.Lock()
					if v := langData[_lang]; v == nil {
						langData[_lang] = map[string]interface{}{}
					}
					for k, v := range data {
						langData[_lang][k] = v
					}
					langLock.Unlock()
				} else {
					fmt.Println("json.Unmarshal", err, newPath)
				}
			} else {
				fmt.Println("ioutil.ReadFile", err, newPath)
			}
		}
	}
}

// GetLangValueByKey ..
func getLangValueByKey(data map[string]interface{}, key string) (ret interface{}) {
	arr := strings.Split(key, ".")
	if len(arr) > 1 {
		if v, ok := data[arr[0]]; ok && v != nil {
			if v2, ok2 := v.(map[string]interface{}); ok2 {
				ret = getLangValueByKey(v2, strings.Join(arr[1:], "."))
			}
		}
	} else if v, ok := data[key]; ok {
		ret = v
	}
	return ret
}

func getStringByKey(data map[string]interface{}, key string) (ret string) {
	val := getLangValueByKey(data, key)
	if v, ok := val.(string); ok {
		ret = v
	}
	return
}

// GetLangInterfaceValue 获取当前语言内容
func GetLangInterfaceValue(lang string, key string) interface{} {
	var value interface{}
	langLock.RLock()
	if _, ok := langData[lang]; !ok {
		lang = defaultLang
	}
	if val, ok := langData[lang]; ok {
		value = getLangValueByKey(val, key)
	}
	langLock.RUnlock()
	return value
}

// GetNowLangValue 获取当前语言内容
func GetNowLangValue(lang string, key string) string {
	value := ""
	langLock.RLock()
	if _, ok := langData[lang]; !ok {
		lang = defaultLang
	}
	if val, ok := langData[lang]; ok {
		value = getStringByKey(val, key)
	}
	langLock.RUnlock()
	return value
}

func GetLangWithParam(lang, key string, params map[string]string) string {
	str := GetNowLangValue(lang, key)
	for k, v := range params {
		str = strings.ReplaceAll(str, k, v)
	}
	return str
}

// GetLangValue 获取语言内容
func GetLangValue(c *gin.Context, key string) string {
	return GetNowLangValue(GetSelectLang(c), key)
}

// GetLangArray ..
func GetLangArray(lang string, keyArr []string) map[string]interface{} {
	ret := map[string]interface{}{}
	langLock.RLock()
	if data, ok := langData[lang]; ok {
		for _, key := range keyArr {
			arr := strings.Split(key, ".")
			if len(arr) > 1 {
				d := data
				for i := 0; i < len(arr); i++ {
					if _data, ok := d[arr[i]]; ok {
						if i == len(arr)-1 {
							ret[key] = _data
						} else if d, ok = _data.(map[string]interface{}); !ok {
							break
						}
					}
				}
			} else if val, ok := data[key]; ok {
				ret[key] = val
			}
		}
	}
	langLock.RUnlock()
	return ret
}
